package com.lft.juc07.readwritelock;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

/**
 * ReadWriteLock
 * 读-读：可以共存！
 * 读-写：不能共存！
 * 写-写：不能共存！
 * <p>
 * 独占锁（写锁），一次只能被一个线程占有。
 * 共享锁（读锁），多个线程可以同时占有。
 */
public class TestReadWriteLock {
	public static void main(String[] args) {
		MyCacheLock myCache = new MyCacheLock();
		// 写入操作的线程
		for (int i = 1; i <= 5; i++) {
			final int temp = i;
			new Thread(() -> {
				myCache.put("" + temp, "我是 " + temp);
			}, String.valueOf(i)).start();
		}
		
		// 读取操作的线程
		for (int i = 1; i <= 5; i++) {
			final int temp = i;
			new Thread(() -> {
				myCache.get("" + temp);
			}, String.valueOf(i)).start();
		}
	}
}

/**
 * 自定义缓存，加了读写锁的。
 */
class MyCacheLock {
	private volatile Map<String, Object> map = new HashMap<>();
	// 读写锁：更加细粒度的控制。
	private ReadWriteLock readWriteLock = new ReentrantReadWriteLock();
	
	/**
	 * 存，写入的时候，只希望同时只有一个线程写。
	 */
	public void put(String key, Object value) {
		readWriteLock.writeLock().lock();
		try {
			System.out.println(Thread.currentThread().getName() + " -> 写入 " + key);
			map.put(key, value);
			System.out.println(Thread.currentThread().getName() + " -> 写入OK！");
		} finally {
			readWriteLock.writeLock().unlock();
		}
	}
	
	/**
	 * 取，读，所有人都可以读！
	 */
	public void get(String key) {
		readWriteLock.readLock().lock();
		try {
			System.out.println(Thread.currentThread().getName() + " -> 读取 " + key);
			String result = (String) map.get(key);
			System.out.println(Thread.currentThread().getName() + " -> 读取OK！其存的数据为 " + result);
		} finally {
			readWriteLock.readLock().unlock();
		}
		
	}
}

/**
 * 自定义缓存，没有加锁的。
 */
class MyCache {
	private volatile Map<String, Object> map = new HashMap<>();
	
	/**
	 * 存，写
	 */
	public void put(String key, Object value) {
		System.out.println(Thread.currentThread().getName() + " -> 写入 " + key);
		map.put(key, value);
		System.out.println(Thread.currentThread().getName() + " -> 写入OK！");
	}
	
	/**
	 * 取，读
	 */
	public void get(String key) {
		System.out.println(Thread.currentThread().getName() + " -> 读取 " + key);
		String result = (String) map.get(key);
		System.out.println(Thread.currentThread().getName() + " -> 读取OK！其存的数据为 " + result);
	}
}

